package com.tsingteng.cosfun.utils;

import android.text.TextUtils;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;



import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import org.apaches.commons.codec.digest.DigestUtils;

/**
 * 签名工具类
 * @author huiwu
 *
 */
public final class SignUtil {
	

	/**
	 * 默认的签名密钥
	 */
	private static final String DEFAULT_SECRET = "#a@!bcdsdjs<>ef@%^_g+-=*(7aweqweqwkjl$";
	
	/**
	 * 默认的签名参数名称
	 */
	private static final String SIGN_PARAM_NAME = "sign";
	
	private static final SignMethod SIGN_METHOD = SignMethod.MD5;
	
	public enum SignMethod{
		MD5,SHA1
	}
	
	private String signName = null;
	
	private SignMethod signMethod = null;
	
	private SignUtil(){
		this(SIGN_PARAM_NAME,SIGN_METHOD);
	}
	
	private SignUtil(String signName,SignMethod signMethod){
		this.signName = signName;
		this.signMethod = signMethod;
	}
	
	
	public static SignUtil build(){
		return new SignUtil();
	}
	
	public static SignUtil build(String signName){
		if (TextUtils.isEmpty(signName)) {
			throw new NullPointerException("Sign param name is null");
		}
		return new SignUtil(signName,SIGN_METHOD);
	}
	
	public static SignUtil build(SignMethod signMethod){
		if (signMethod==null) {
			throw new NullPointerException("Sign param name is null");
		}
		return new SignUtil(SIGN_PARAM_NAME,signMethod);
	}
	
	public static SignUtil build(String signName,SignMethod signMethod){
		if (TextUtils.isEmpty(signName)||signMethod==null) {
			throw new NullPointerException("Sign param name is null");
		}
		if (signMethod!=SignMethod.MD5&&signMethod!=SignMethod.SHA1) {
			throw new IllegalArgumentException("Not support sign method "+signMethod);
		}
		return new SignUtil(signName,signMethod);
	}
	
	/**
	 * 使用默认的secret对data签名
	 * @param data
	 * @return
	 */
	public  String sign(Map<String,String> data){

		return sign(data, DEFAULT_SECRET);
	}
	
	/**
	 * 对data使用signKey进行签名
	 * @param data
	 * @param signSecret
	 * @return
	 */
	public  String sign(Map<String,String> data,String signSecret){
		
		String req = mapToUrlParam(data, signSecret);
//		LogUtils.i("验签字符串是:{}
		System.out.println("验签字符串是"+req);
		if (signMethod==SignMethod.MD5) {
//			System.out.println("加密的签名："+ DigestUtils.md5Hex(req).toUpperCase()+"-----"+ org.apache.commons.codec.binary.StringUtils.getBytesUtf8(req).toString());
			return DigestUtils.md5Hex(req).toUpperCase();
		}else{
			return null;
		}
	}

	
	/**0
	 * 使用默认的KEY签名
	 * @param data 格式如a=1&b=2&c=3
	 * @return
	 */
	public  String sign(String data){
		if (TextUtils.isEmpty(data)) {
			return null;
		}
		return sign(data,DEFAULT_SECRET);
	}
	
	/**
	 * 
	 * @param data 格式如a=1&b=2&c=3
	 * @param signSecret 签名key
	 * @return
	 */
	public  String sign(String data,String signSecret){
		if (TextUtils.isEmpty(data)) {
			return null;
		}
		Map<String,String> params = urlParamToMap(data);
		return sign(params, signSecret);
	}
	
	
	public  boolean validate(String data,String signSecret){
		if (TextUtils.isEmpty(data)||TextUtils.isEmpty(signSecret)) {
			return false;
		}
		Map<String,String> params = urlParamToMap(data);
		return validate(params, signSecret);
	}
	
	public  boolean validate(String data){
		return validate(data, DEFAULT_SECRET);
	}
	
	/**
	 * 验证签名是否正确，data中必须有签名参数
	 * @param data
	 * @return
	 */
	public  boolean validate(Map<String,String> data){
		return validate(data, DEFAULT_SECRET);
	}
	
	/**
	 * 验证签名是否正确，data中必须有签名参数
	 * @param data
	 * @param signSecret
	 * @return
	 */
	public  boolean validate(Map<String,String> data,String signSecret){
		if (data==null||data.isEmpty()||!data.containsKey(signName)) {
			return false;
		}
		String sign = data.get(signName);
		System.out.println("解析的签名："+sign);
		data.remove(signName);
		return sign.equals(sign(data, signSecret));
	}
	
	private static String mapToUrlParam(Map<String, String> data, String signSecret) {
		String str = Joiner.on("#").withKeyValueSeparator("=").join(data);
        List<String> list = Lists.newArrayList(Splitter.on("#").trimResults().splitToList(str));
        Collections.sort(list);
        String req = Joiner.on("&").join(list).concat(signSecret);
		return req;
	}
	
	private static Map<String,String> urlParamToMap(String data){
		if (TextUtils.isEmpty(data)) {
			return null;
		}
		Map<String,String> params = Splitter.on("&").omitEmptyStrings().withKeyValueSeparator("=").split(data);
		Map<String,String> m = Maps.newHashMap();
		if (params!=null&&!params.isEmpty()){
			params.forEach((k,v)-> {if (TextUtils.isEmpty(v)) {
				m.put(k,v);
			}});
		}
		return m;
	}
	
	public static void main(String[] args) {
//		String url = "gid=test&mobile=18842867528&plat=1&timestamp=1533539853390&verify_type=1&sign=2718802D0C29A47108E9ECDCD166E262";
		Map map = new HashMap();
		map.put("gid", "gid");
		map.put("plat", 2);
				map.put("mobile", "1520151237");
                map.put("verify_code", "1234");map.put("timestamp",1533723695518l);
//		System.out.println(url);
//		boolean v1 = SignUtil.build(SignMethod.MD5).validate(url);

//        System.out.println(v1);
		System.out.println("加密结果："+SignUtil.build().sign(map));
		map.put("sign","005961D90F51C3D16A9D8DE32D9D0D96");
        boolean v2 = SignUtil.build(SignMethod.MD5).validate(map);
        System.out.println(v2);

	}
	
	
}